/*
 *  Copyright 2009 Johan Maasing.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package com.google.code.pj2r.beanutils;

import com.google.code.pj2r.MarshallingException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

/**
 * Marshaller that reads the request body as a x-www-formencoded stream to extract the incoming data.
 */
public class BodyFormencodedMarshaller extends BeanUtilsMarshaller {

	private String defaultEncoding = "ISO-8859-1";
	private final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded";

	public BodyFormencodedMarshaller() {
	}

	/*
	 * Set the character encoding to use (needed for Jetty that sends using UTF-8).
	 * @param encoding
	 *
	public BodyFormencodedMarshaller(final String encoding) {
	this.defaultEncoding = encoding;
	}
	 */
	
	/**
	 * Extract the incoming data from the request body. Assumes the content is x-www-formencoded data.
	 * @param request
	 * @return
	 */
	protected Map getDataMap(HttpServletRequest request) throws IOException, MarshallingException {
		String contentType = request.getContentType();
		if (contentType != null) {
			contentType = contentType.trim() ;
		}
		if ((contentType != null) && (!contentType.startsWith(FORM_CONTENT_TYPE))) {
			throw new MarshallingException(
					"Unable to marshall request, expected content type to be: " +
					FORM_CONTENT_TYPE +
					" but was " +
					contentType);
		}
		String encoding = (request.getCharacterEncoding() != null) ? request.getCharacterEncoding() : defaultEncoding;
		HashMap resultBuffer = new HashMap();
		InputStream stream = request.getInputStream();
		StringBuffer requestBody = new StringBuffer();
		int ch = stream.read();
		while (ch != -1) {
			requestBody.append((char) ch);
			ch = stream.read();
		}
		String[] params = requestBody.toString().split("&");
		for (int n = 0; n < params.length; n++) {
			addParameter(resultBuffer, params[n], encoding);
		}

		// Convert lists to arrays
		HashMap result = new HashMap();
		for (Iterator i = result.keySet().iterator(); i.hasNext();) {
            String key = (String) i.next();
            ArrayList list = (ArrayList) resultBuffer.get(key);
            String[] values = (String[]) list.toArray(new String[0]);
			result.put(key, values);
		}
		return result;
	}

	private void addParameter(HashMap resultBuffer, String parameter, String encoding) throws UnsupportedEncodingException {
		if ((parameter != null) && (parameter.length() > 1)) {
			String[] parts = parameter.split("=");
			// Is there a key
			if (parts.length > 0) {
				if (parts[0].length() > 0) {
					String key = URLDecoder.decode(parts[0], encoding);

					// Get the value storage
					ArrayList valueBuffer = (ArrayList) resultBuffer.get(key);
					if (valueBuffer == null) {
						valueBuffer = new ArrayList();
					}

					// Get the value (or if none set to empty string)
					String value = "";
					if ((parts.length > 1) && (parts[1].length() > 0)) {
						value = URLDecoder.decode(parts[1], encoding);
					}

					valueBuffer.add(value);
					resultBuffer.put(key, valueBuffer);
				}
			}
		}
	}
}
